package org.goldfish.cookied_chatroom02.database;

import jakarta.servlet.ServletContext;
import org.goldfish.cookied_chatroom02.dao.Dao;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class DaoImpl implements Dao {
    private static DaoImpl instance;
    private final ConnectionPool pool;

    private DaoImpl(ServletContext context) throws IOException, SQLException, ClassNotFoundException {
        pool = new ConnectionPool(context);
    }

    public static void init(ServletContext context) throws SQLException, IOException, ClassNotFoundException {
        if (instance == null)
            instance = new DaoImpl(context);
    }

    public static DaoImpl getInstance() {
        return instance;
    }

    @Override
    public int update(String SQL, Object target_id, Object[] bindArgs) throws SQLException {
        Connection connection=null;
        try {
            connection = pool.take();
            int rows_affected;
            try (PreparedStatement statement = connection.prepareStatement(SQL)) {
                int index = 0;
                if (target_id != null)
                    statement.setObject(++index, target_id);
                if (bindArgs != null)
                    for (Object bindArg : bindArgs)
                        statement.setObject(++index, bindArg);
                rows_affected = statement.executeUpdate();
            }

            return rows_affected;
        } catch (SQLException | InterruptedException sqlException) {
            sqlException.printStackTrace();
            return -1;
        } finally {
            if (connection != null)
                pool.returnConnection(connection);
        }
    }

    @Override
    @Nullable
    public List<List<Object>> query(String SQL, Object[] conditions) {
        List<List<Object>> list = new ArrayList<>();
        try {
            Connection connection = pool.take();
            try (PreparedStatement preparedStatement = connection.prepareStatement(SQL)) {
                int index = 0;
                if (conditions != null)
                    for (Object condition : conditions)
                        preparedStatement.setObject(++index, condition);
                try (ResultSet set = preparedStatement.executeQuery()) {
                    while (set.next()) {
                        List<Object> row = new ArrayList<>();
                        for (int i = 1; i <= set.getMetaData().getColumnCount(); i++)
                            row.add(set.getObject(i));
                        list.add(row);
                    }
                }
            }
            pool.returnConnection(connection);
            return list;
        } catch (InterruptedException | SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    public void destroy() throws SQLException {
        pool.closeAll();
    }
}
